package dao

import (
	"errors"
	"fmt"
	"html/template"
	"sync"
	"time"
)

type TypeName struct {
	Id        int    `json:"id"`
	Name      string `json:"name"`
	Fid       int    `json:"fid"`
	FName     string `json:"f_name"`
	ReadLevel int    `json:"read_level"`
	IsShow    int    `json:"is_show"`
	AddTime   string `json:"add_time"`
}

func (t *TypeName) ToHtml(byAdmin bool) template.HTML {

	url := ""
	if byAdmin {
		url = "###"
	} else {
		url = "/search?"
	}
	str := ""
	if t.Fid != 0 {
		str += fmt.Sprintf("<a href='%stype=%d'>%s</a> - ", url, t.Fid, t.FName)
	}
	str += fmt.Sprintf("<a href='%stype=%d'>%s</a>", url, t.Id, t.Name)

	return template.HTML(str)
}

/**
Info
*/
func (t *TypeName) Info() (err error) {

	if t.Id <= 0 {
		return errors.New("id is null")
	}

	sql := fmt.Sprintf("select `id`,`name`,`fid`,`fid_name`,`read_level`,`is_show`,`add_time` from `bg_posts_type` where id=%d", t.Id)
	if Db == nil {
		InitMysql()
	}

	err = Db.QueryRow(sql).Scan(&t.Id, &t.Name, &t.Fid, &t.FName, &t.ReadLevel, &t.IsShow, &t.AddTime)
	if err != nil {
		return
	}

	return
}

/**
Add
*/
func (t *TypeName) Add() (err error) {
	if Db == nil {
		InitMysql()
	}

	t.AddTime = time.Now().Format(TimeLayout)

	sql := fmt.Sprintf("insert into bg_posts_type set name='%s',fid=%d,fid_name='%s',read_level=%d,is_show=%d,add_time='%s'", t.Name, t.Fid, t.FName, t.ReadLevel, t.IsShow, t.AddTime)
	Result, err := Db.Exec(sql)
	if err != nil {
		fmt.Println(err)
		return
	}

	id, err := Result.LastInsertId()
	if err != nil {
		fmt.Println(err)
		return
	}
	t.Id = int(id)

	return
}

/**
Update
*/
func (t *TypeName) Update() (err error) {
	if Db == nil {
		InitMysql()
	}

	sql := fmt.Sprintf("update bg_posts_type set name='%s',fid=%d,read_level=%d,is_show=%d", t.Name, t.Fid, t.ReadLevel, t.IsShow)
	res, err := Db.Exec(sql)
	if err != nil {
		return
	}
	if num, err := res.RowsAffected(); num == 0 || err != nil {
		return errors.New("update error")
	}

	return
}

/**
Delete
*/
func (t *TypeName) Delete() (err error) {

	return
}

/**
添加时检查Fid
*/
func (t TypeName) CheckAddFid(fid int) (isOk bool, errMsg string) {
	if fid == 0 {
		return true, ""
	}

	t.Id = fid
	err := t.Info()
	if err != nil {
		errMsg = "data not find"
		return
	}

	if t.Fid != 0 {
		errMsg = "can not be add"
		return
	}

	isOk = true

	return
}

/**
名称检查
*/
func (t TypeName) CheckAddName(name string, fid int) (isOk bool, errMsg string) {

	if name == "" {
		return false, "name is empty"
	}

	if len(name) < 2 {
		return false, "name is too short"
	}

	if len(name) > 16 {
		return false, "name is too long"
	}

	if Db == nil {
		InitMysql()
	}
	var num int
	Db.QueryRow("select count(*) from bg_posts_type where fid=? and name='?'", fid, name).Scan(&num)
	if num >= 1 {
		return false, "name is repeat"
	}

	return true, ""
}

/**
获取名称
*/
func (t TypeName) GetTypeName(id int) (name string) {
	if id == 0 {
		return ""
	}

	if Db == nil {
		InitMysql()
	}
	Db.QueryRow("select name from bg_posts_type where id=? ", id).Scan(&name)

	return
}

/**
 * 获取分类列表
 * @param baseId 父级分类
 */
func GetTypeList(baseId int, isShow int) (types []TypeListData) {

	var isShowStr = ""
	if isShow == 1 {
		isShowStr = "and is_show=1 "
	} else if isShow == 0 {
		isShowStr = "and is_show=0 "
	} else {
		isShowStr = ""
	}
	//先获取所有的顶级(一级)分类
	sql := fmt.Sprintf("select `id`,`name`,IFNULL(`fid`,0),IFNULL(`fid_name`,''), `read_level`,`is_show` from bg_posts_type where fid=%d %s order by id ", baseId, isShowStr)
	if Db == nil {
		InitMysql()
	}

	rows, err := Db.Query(sql)
	if err != nil {
		return
	}
	defer rows.Close()

	var wg sync.WaitGroup //声明一个等待组
	for rows.Next() {

		wg.Add(1)

		var t TypeListData
		var tIsShow int
		err := rows.Scan(&t.Id, &t.Name, &t.Fid, &t.FidName, &t.ReadLevel, &tIsShow)
		if err != nil {
			fmt.Println(err.Error())
			return
		}

		if tIsShow == 1 {
			t.IsShow = true
		} else {
			t.IsShow = false
		}

		t.PostNum += GetPostNum(t.Id, tIsShow)
		t.Child = GetTypeList(t.Id, tIsShow)
		types = append(types, t)

		wg.Done()
	}

	wg.Wait() //塞到计数器的值为0

	return
}

/**
通过父级ID找所有下级的id
*/
func GetSonIds(baseId int) (ids []int) {

	sql := fmt.Sprintf("select id from `bg_posts_type` where fid=%d ", baseId)
	if Db == nil {
		InitMysql()
	}

	rows, err := Db.Query(sql)
	if err != nil {
		return
	}
	defer rows.Close()

	var id int
	for rows.Next() {
		err := rows.Scan(&id)
		if err != nil {
			fmt.Println(err.Error())
			return
		}
		ids = append(ids, id)
	}

	return
}

/**
获取分类的名称
*/
func GetPostTypeInfo(typeId int) (info TypeName) {

	var dict map[int]TypeName

	if len(CacheTypesNames.Lists) == 0 || time.Now().Unix()-CacheTypesNames.CachedTime > 300 {
		sql := "select id,name,fid,fid_name,read_level,is_show,add_time from `bg_posts_type` where 1 "
		if Db == nil {
			InitMysql()
		}

		rows, err := Db.Query(sql)
		if err != nil {
			return
		}
		defer rows.Close()

		dict := make(map[int]TypeName)
		for rows.Next() {
			var d TypeName

			err := rows.Scan(&d.Id, &d.Name, &d.Fid, &d.FName, &d.ReadLevel, &d.IsShow, &d.AddTime)
			if err != nil {
				fmt.Println(err.Error())
				return
			}
			dict[d.Id] = TypeName{Id: d.Id, Name: d.Name, Fid: d.Fid, FName: d.FName, ReadLevel: d.ReadLevel, IsShow: d.IsShow, AddTime: d.AddTime}
		}
		info = dict[typeId]
		CacheTypesNames.Lists = dict
		CacheTypesNames.CachedTime = time.Now().Unix()
	} else {
		dict = CacheTypesNames.Lists
		info = dict[typeId]
	}

	return
}

type TypesNames struct {
	Lists      map[int]TypeName `json:"lists"`
	CachedTime int64            `json:"cached_time"`
}

var CacheTypesNames TypesNames

/**
添加文章时对文章分类进行检查
必须是已经存在的二级分类
*/
func CheckAddPostTypeId(id int64) (isOk bool) {
	sql := fmt.Sprintf("select count(*) as num from `bg_posts_type` where id=%d and fid <>0 limit 1", id)
	if Db == nil {
		InitMysql()
	}

	rows := Db.QueryRow(sql)
	var num int = 0
	err := rows.Scan(&num)
	if err != nil {
		return
	}

	if num >= 1 {
		isOk = true
	}

	return
}
